﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Security.Cryptography;
using System.IO;
using UCVerificationComponent;
using FormDialog;

namespace AESEncrypt
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            label6.Text = "密码不会以任何形式存储在任何位置\n\n请牢记密码，若忘记密码，则加密的内容将无法恢复\n\n解密时只需输入一遍密码即可";
            lineProgressBar1.Visible = false;
            verificationComponent1.SetVerificationRequired(textBox1, true);
            verificationComponent1.SetVerificationRequired(textBox2, true);
            verificationComponent1.SetVerificationModel(textBox1, UCVerificationComponent.VerificationModel.PassWord);
            verificationComponent1.SetVerificationModel(textBox2, UCVerificationComponent.VerificationModel.IP);
        }

        //初始化密钥向量
        private static string _aesKeyVector = "q2T_=R/*33vc";
     //   private static byte[] _aesKeyVector = { 0x71, 0x32, 0x54, 0x5F, 0x3D, 0x52, 0x2F, 0x2A, 0x33, 0x33, 0x76, 0x63 };

        private void Browse_btn_Click(object sender, EventArgs e)
        {
            openFileDialog1.FileName = "加密/解密文件";
            if(openFileDialog1.ShowDialog()==DialogResult.OK)
            {
                textBox1.Clear();
                textBox2.Clear();
                textBox3.Text = openFileDialog1.FileName;
                textBox3.Select(textBox3.TextLength, 0);
            }
        }

        private void Encrypt_btn_Click(object sender, EventArgs e)
        {
            if(string.IsNullOrEmpty(textBox3.Text))
            {
                FrmDialog.ShowDialog(this, "请选择待加密/解密文件", "提示", false, false, new Size(-150, -90));
                return;
            }
            if (!verificationComponent1.Verification(textBox1))
            {
                textBox1.SelectAll();
                textBox1.Focus();
                return;
            }
            if(!checkBox1.Checked)
            {
                if (textBox2.Text != textBox1.Text)
                {
                    verificationComponent1.SetVerificationErrorMsg(textBox2, "两次输入的密码不一致");
                    verificationComponent1.Verification(textBox2);
                    textBox2.SelectAll();
                    textBox2.Focus();
                    return;
                }
            }           
            lineProgressBar1.Visible = true;
            lineProgressBar1.Value = 0;
            backgroundWorker1.RunWorkerAsync();
        }

        private void Decrypt_btn_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(textBox3.Text))
            {
                FrmDialog.ShowDialog(this, "请选择待加密/解密文件", "提示", false, false, new Size(-150, -90));
                return;
            }
            if (string.IsNullOrEmpty(textBox1.Text))
            {
                FrmDialog.ShowDialog(this, "请输入密码", "提示", false, false, new Size(-150, -90));
                return;
            }
            lineProgressBar1.Visible = true;
            lineProgressBar1.Value = 0;
            backgroundWorker2.RunWorkerAsync();
        }

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            string KeyVector = _aesKeyVector;//密钥向量
            string path = Path.GetDirectoryName(textBox3.Text);
            string name = Path.GetFileName(textBox3.Text);
            name += ".En";
            #region   加密
            FileStream sr = new FileStream(textBox3.Text, FileMode.Open, FileAccess.Read);
            MessageBox.Show(path);
            FileStream sw = new FileStream(path + "\\" + name, FileMode.Create, FileAccess.Write);

            if (sr.Length > 50 * 1024 * 1024)//如果文件大于50M，采取分块加密，按50MB读写
            {
                byte[] mybyte = new byte[52428800];//每50MB加密一次                  
                int numBytesRead = 52428800;//每次加密的流大小
                long leftBytes = sr.Length;//剩余需要加密的流大小
                long readBytes = 0;//已经读取的流大小
                //每50MB加密后会变成50MB+16B
                byte[] encrpy = new byte[52428816];
                while (true)
                {
                    if (leftBytes > numBytesRead)
                    {
                        sr.Read(mybyte, 0, mybyte.Length);
                        encrpy = AES_EnorDecrypt.AESEncrypt(mybyte, textBox1.Text, KeyVector);
                        sw.Write(encrpy, 0, encrpy.Length);                       
                        leftBytes -= numBytesRead;
                        readBytes += numBytesRead;
                        backgroundWorker1.ReportProgress((int)(readBytes * 100 / sr.Length));
                    }
                    else//重新设定读取流大小，避免最后多余空值
                    {
                        byte[] newByte = new byte[leftBytes];
                        sr.Read(newByte, 0, newByte.Length);
                        byte[] newWriteByte;
                        newWriteByte = AES_EnorDecrypt.AESEncrypt(newByte, textBox1.Text, KeyVector);
                        sw.Write(newWriteByte, 0, newWriteByte.Length);
                        readBytes += leftBytes;
                        backgroundWorker1.ReportProgress((int)(readBytes * 100 / sr.Length));
                        break;
                    }
                }               
            }
            else
            {
                byte[] mybyte = new byte[sr.Length];
                sr.Read(mybyte, 0, (int)sr.Length);
                mybyte = AES_EnorDecrypt.AESEncrypt(mybyte, textBox1.Text, KeyVector);
                sw.Write(mybyte, 0, mybyte.Length);
                backgroundWorker1.ReportProgress(100);
            }

            sr.Close();
            sw.Close();   
            
            #endregion
        }

        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            lineProgressBar1.Value = e.ProgressPercentage;
        }

        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (FrmDialog.ShowDialog(this, "加密完成，是否删除源文件？", "询问", true, true, new Size(-150, -90), "是", "否") == DialogResult.OK)
            {
                File.Delete(textBox3.Text);
            }
            lineProgressBar1.Visible = false;
        }

        private void backgroundWorker2_DoWork(object sender, DoWorkEventArgs e)
        {
            try
            {
                string KeyVector = _aesKeyVector;//密钥向量
                string path = Path.GetDirectoryName(textBox3.Text);
                string name = Path.GetFileName(textBox3.Text);
                if (name.EndsWith(".En"))
                {
                    name = name.Remove(name.Length - 3, 3);
                }

                #region  解密
                FileStream sr = new FileStream(textBox3.Text, FileMode.Open, FileAccess.Read);
                FileStream sw = new FileStream(path + "\\" + name, FileMode.Create, FileAccess.Write);
                
                if (sr.Length > 50 * 1024 * 1024)//如果文件大于50M，采取分块解密，按50MB读写
                {
                    byte[] mybyte = new byte[52428816];//解密缓冲区50MB+16B
                    byte[] decrpt = new byte[52428800];//解密后的50MB
                    int numBytesRead = 52428816;//每次解密的流大小
                    long leftBytes = sr.Length;//剩余需要解密的流大小
                    long readBytes = 0;//已经读取的流大小
                    try
                    {
                        while (true)
                        {
                            if (leftBytes > numBytesRead)
                            {
                                sr.Read(mybyte, 0, mybyte.Length);
                                decrpt = AES_EnorDecrypt.AESDecrypt(mybyte, textBox1.Text, KeyVector);                               
                                sw.Write(decrpt, 0, decrpt.Length);
                                leftBytes -= numBytesRead;
                                readBytes += numBytesRead;
                                backgroundWorker2.ReportProgress((int)(readBytes * 100 / sr.Length));
                            }
                            else//重新设定读取流大小，避免最后多余空值
                            {
                                byte[] newByte = new byte[leftBytes];
                                sr.Read(newByte, 0, newByte.Length);
                                byte[] newWriteByte;
                                newWriteByte = AES_EnorDecrypt.AESDecrypt(newByte, textBox1.Text, KeyVector);
                                sw.Write(newWriteByte, 0, newWriteByte.Length);
                                readBytes += leftBytes;
                                backgroundWorker2.ReportProgress((int)(readBytes * 100 / sr.Length));
                                break;
                            }
                        }
                    }
                    catch
                    {
                        sr.Close();
                        sw.Close();
                        File.Delete(path + "\\" + name);
                        e.Cancel = true;
                    }
                    sr.Close();
                    sw.Close();
                }
                else
                {
                    byte[] mybyte = new byte[(int)sr.Length];
                    sr.Read(mybyte, 0, (int)sr.Length);
                    try
                    {
                        mybyte = AES_EnorDecrypt.AESDecrypt(mybyte, textBox1.Text, KeyVector);
                        sw.Write(mybyte, 0, mybyte.Length);
                        backgroundWorker2.ReportProgress(100);
                    }
                    catch
                    {
                        sr.Close();
                        sw.Close();
                        File.Delete(path + "\\" + name);
                        e.Cancel = true;
                    }
                    sr.Close();
                    sw.Close();
                }                        
                #endregion                
            }
            catch
            {
                e.Cancel = true;
            }
        }

        private void backgroundWorker2_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            lineProgressBar1.Value = e.ProgressPercentage;
        } 

        private void backgroundWorker2_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if(e.Cancelled)
            {
                FrmDialog.ShowDialog(this, "解密失败\n密码错误或加密文件被篡改，无法解密", "警告", false, false, new Size(-120, -90));
                lineProgressBar1.Visible = false;
            }
            else
            {
                if (FrmDialog.ShowDialog(this, "解密完成，是否删除加密文件？", "询问", true, true, new Size(-150, -90), "是", "否") == DialogResult.OK)
                {
                    File.Delete(textBox3.Text);
                }
                lineProgressBar1.Visible = false;
            }
        }

        private void Form1_DragDrop(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                textBox1.Clear();
                textBox2.Clear();
                textBox3.Text = ((string[])e.Data.GetData(DataFormats.FileDrop.ToString()))[0];
                textBox3.Select(textBox3.TextLength, 0);
            }
        }

        private void Form1_DragOver(object sender, DragEventArgs e)
        {
            e.Effect = DragDropEffects.Copy;
        }

        private void checkBox1_CheckedChangeEvent(object sender, EventArgs e)
        {
            textBox1.UseSystemPasswordChar = !checkBox1.Checked;
            label2.Visible = !checkBox1.Checked;
            textBox2.Visible = !checkBox1.Checked;
        }

        private void textBox1_TextChanged(object sender, EventArgs e)
        {

        }

        private void label6_Click(object sender, EventArgs e)
        {

        }        
    }
}
